package com.swt.gap.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.swt.gap.common.PageResult;
import com.swt.gap.common.PermissionService;
import com.swt.gap.common.constant.RedisConstant;
import com.swt.gap.common.graph.GraphService;
import com.swt.gap.config.ServerConfig;
import com.swt.gap.dao.*;
import com.swt.gap.model.dto.SubscribeRuleDTO;
import com.swt.gap.model.entity.*;
import com.swt.gap.model.vo.TaskInfoVO;
import com.swt.gap.model.vo.TaskVO;
import com.swt.gap.model.vo.*;
import com.swt.gap.model.vo.taskresult.AnalysisResultVO;
import com.swt.gap.model.vo.taskresult.TaskAnalysisVO;
import com.swt.gap.service.SysGroupService;
import com.swt.gap.service.TaskGraphData;
import com.swt.gap.service.TaskService;
import com.swt.gap.util.UserLoginUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class TaskServiceImpl implements TaskService {

    private final TaskDao taskDao;
    private final SysUserMapper userMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final TaskFileMapper taskFileMapper;
    private final GraphService graphService;
    private final TaskResultMapper taskResultMapper;
    private final TaskAccessLogMapper taskAccessLogMapper;
    private final TaskGraphData taskGraphData;
    private final TaskSubscribeRuleDao taskSubscribeRuleDao;
    private final SysRoleMapper sysRoleMapper;
    private final ServerConfig serverConfig;
    private final SysGroupService sysGroupService;
    private final PermissionService permissionService;


    public TaskServiceImpl(TaskDao taskDao, SysUserMapper userMapper,
                           SysUserRoleMapper userRoleMapper,
                           TaskFileMapper taskFileMapper, GraphService graphService,
                           TaskResultMapper taskResultMapper,
                           TaskAccessLogMapper taskAccessLogMapper,
                           TaskGraphData taskGraphData,
                           TaskSubscribeRuleDao taskSubscribeRuleDao,
                           SysRoleMapper sysRoleMapper,
                           ServerConfig serverConfig,
                           SysGroupService sysGroupService,
                           PermissionService permissionService) {
        this.taskDao = taskDao;
        this.userMapper = userMapper;
        this.userRoleMapper = userRoleMapper;
        this.taskFileMapper = taskFileMapper;
        this.graphService = graphService;
        this.taskResultMapper = taskResultMapper;
        this.taskAccessLogMapper = taskAccessLogMapper;
        this.taskGraphData = taskGraphData;
        this.taskSubscribeRuleDao = taskSubscribeRuleDao;
        this.sysRoleMapper = sysRoleMapper;
        this.serverConfig = serverConfig;
        this.sysGroupService = sysGroupService;
        this.permissionService = permissionService;
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public Integer addNewTask(Task task) {
        //获取创建者信息
        SysUser sysUser = UserLoginUtils.getUser();
        task.setCreatedBy(sysUser.getUserId());
        //新建任务信息
        task.setCreatedTime(new Date());
        task.setStatus(1);
        task.setDeleted(false);
        if(null != task.getHasPassword() && task.getHasPassword() && !StringUtils.isEmpty(task.getPassword())) {
            task.setPassword(SecureUtil.md5(task.getPassword()));
        } else {
            task.setPassword("");
        }
        int result = taskDao.insertSelective(task);

        taskGraphData.saveToRedis(RedisConstant.KEY_PREFIX_TASK + task.getTaskId(), RedisConstant.SAVE_FINISHED);
        return result;
    }

    @Override
    public Boolean judgeTaskName(String taskName, Integer taskId) {
        Integer userId = UserLoginUtils.getUserId();
        Task record = taskDao.selectByTaskName(taskName, userId);
        if(record == null){
            return false;
        }
        if(taskId != null){
            return !taskId.equals(record.getTaskId());
        }
        return true;
    }

    @Override
    public TaskInfoVO getTaskInfoById(Integer taskId) {
        Task task = taskDao.selectByPrimaryKey(taskId);
        TaskInfoVO taskInfoVO = new TaskInfoVO();
        BeanUtils.copyProperties(task, taskInfoVO);

        SysUser record = userMapper.selectByPrimaryKey(task.getCreatedBy());
        taskInfoVO.setCreatedName(record.getUserName());
        List<TaskSubscribeRule> rules = taskSubscribeRuleDao.selectByTaskId(taskId);
        if (!CollectionUtils.isEmpty(rules)) {
            List<SubscribeRuleDTO> subscribeRules = JSONObject.parseArray(rules.get(0).getRule().toJSONString(), SubscribeRuleDTO.class);
            List<String> events = subscribeRules.stream()
                    .map(SubscribeRuleDTO::getOntologyNodeName)
                    .collect(Collectors.toList());
            List<String> elements = new ArrayList<>();
            subscribeRules.forEach(r ->
                elements.addAll(r.getElements().stream()
                        .map(e -> e.getElement() + "-" + e.getSubscribeValue())
                        .collect(Collectors.toList()))
            );
            taskInfoVO.setSubscribeEventTypes(events);
            taskInfoVO.setSubscribeElementTypes(elements);
        }
        return taskInfoVO;
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public Integer updateTaskInfo(TaskUpdateVO task) {
        Task newTask = new Task();
        newTask.setUpdateTime(new Date());
        newTask.setTaskId(task.getTaskId());
        newTask.setTaskName(task.getTaskName());
        newTask.setDescription(task.getDescription());
        newTask.setHasPassword(task.getHasPassword());
        if(null !=task.getHasPassword() && task.getHasPassword() && !StringUtils.isEmpty(task.getPassword())) {
            newTask.setPassword(SecureUtil.md5(task.getPassword()));
        } else if(null !=task.getHasPassword() && !task.getHasPassword()) {
            newTask.setPassword("");
        }
        return taskDao.updateByPrimaryKeySelective(newTask);
//        taskUserMapper.deleteByTaskId(task.getTaskId());
//        for (Integer userId : task.getUserIds()) {
//            TaskUser taskUser = new TaskUser();
//            taskUser.setUserId(userId);
//            taskUser.setTaskId(task.getTaskId());
//            taskUserMapper.insertSelective(taskUser);
//        }
//        return result;
    }

    @Override
    public Integer putTaskToRecycleBin(Integer taskId) {
        return taskDao.deleteTask(taskId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteTasks(List<Integer> taskIds) {
        int result = 0;
        //先删除和任务相关的内容
        for (Integer taskId : taskIds) {
            taskFileMapper.deleteByTaskId(taskId);
            taskResultMapper.deleteByTaskId(taskId);
            result += taskDao.deleteByPrimaryKey(taskId);

            graphService.deleteGraphByTaskId(taskId);
        }

        return result;
    }

    @Override
    public Integer restoreTasks(List<Integer> taskIds) {
        int result = 0;
        for (Integer taskId : taskIds) {
            result += taskDao.restoreTask(taskId);
        }
        return result;
    }

    @Override
    public Boolean judgeAuthority(Integer taskId) {
        SysUser sysUser = UserLoginUtils.getUser();
        Task task = taskDao.selectByPrimaryKey(taskId);
        return task.getCreatedBy().equals(sysUser.getUserId()) ||
                userRoleMapper.selectRoleIdByuserId(sysUser.getUserId()).equals(1);
    }

    @Override
    public Integer updateStatus(Integer taskId, Integer status) {
        Task newTask = new Task();
        newTask.setTaskId(taskId);
        newTask.setUpdateTime(new Date());
        newTask.setStatus(status);
        return taskDao.updateByPrimaryKeySelective(newTask);
    }


    @Override
    public PageResult<TaskVO> getTaskByKey(Integer pageNum, Integer pageSize,String keyword,Integer userId) {
//        MyTaskVO myTaskVO = new MyTaskVO();
        //判断页数
        if (null != pageNum && null != pageSize) {
            PageHelper.startPage(pageNum, pageSize);
        }
        Page<TaskVO> taskInfoVoPage = taskDao.getTaskByKey2(keyword,userId);
//        List<TaskVO> recentTask=taskMapper.getRecentTaskByKey(keyword,userId);
        setPermission(userId,taskInfoVoPage);
//        setPermission(userId,recentTask);
//        myTaskVO.setRecentTask(recentTask);
//        myTaskVO.setHistoryTask(new PageResult<>(taskInfoVoPage));
//        return myTaskVO;
        return new PageResult<>(taskInfoVoPage);
    }

    @Override
    public  PageResult<TaskVO> getJoinTaskByKey(Integer pageNum, Integer pageSize, String keyword, Integer userId) {
//        MyTaskVO myTaskVO = new MyTaskVO();
        if (null != pageNum && null != pageSize) {
            PageHelper.startPage(pageNum, pageSize);
        }
        Page<TaskVO> taskInfoVoPage = taskDao.getJoinTaskByKey2(keyword,userId);
//        List<TaskVO> recentJoinTask = taskMapper.getRecentJoinTaskByKey(keyword,userId);
//
        setPermission(userId,taskInfoVoPage);
//        setPermission(userId,recentJoinTask);

//        myTaskVO.setRecentTask(recentJoinTask);
//        myTaskVO.setHistoryTask(new PageResult<>(taskInfoVoPage));
        return new PageResult<>(taskInfoVoPage);
    }

    @Override
    public PageResult<TaskVO> getTaskByStatus(Integer pageNum, Integer pageSize, String keyword, Integer userId,Integer status) {

        List<Integer> userIds = sysGroupService.listSameGroupUserByUserId(userId);
        //这里有坑 当一个方法中有多个查询语句时，只有紧跟在PageHelper.starPage()方法后的查询结果才会分页。
        if (null != pageNum && null != pageSize) {
            PageHelper.startPage(pageNum, pageSize);
        }
        Page<TaskVO> taskInfoVoPage2 = taskDao.getTaskByStatusAndGroup2(keyword,userIds,status);

        taskInfoVoPage2.getResult().forEach(t -> {
            List<TaskResultWithBLOBs> results = taskResultMapper.getResults(t.getTaskId());
            t.setResultCount(results.size());
        });


        setPermission(userId,taskInfoVoPage2);
        return new PageResult<>(taskInfoVoPage2);
    }

    @Override
    public PageResult<TaskVO> getDeleteTaskByKey(Integer pageNum, Integer pageSize, String keyword, Integer userId) {
        if (null != pageNum && null != pageSize) {
            PageHelper.startPage(pageNum, pageSize);
        }
        Page<TaskVO> taskInfoVoPage = taskDao.getDeleTaskBykey(keyword,userId);
        return new PageResult<>(taskInfoVoPage);
    }


    @Override
    public List<Task> getAccessTask(String keyword, Integer userId) {
        return taskDao.getAccessTask(keyword, userId);
    }

    @Override
    public Integer updateAccessLog(Integer taskId, Integer userId) {

            TaskAccessLog taskAccessLog = new TaskAccessLog();
            taskAccessLog.setTaskId(taskId);
            taskAccessLog.setUserId(userId);
            taskAccessLog.setAnalysedTime(new Date());
            return taskAccessLogMapper.insertSelective(taskAccessLog);

    }

    @Override
    public List<TaskAnalysisVO> getLastAnalysisTasks(Integer userId) {
        List<Integer> userIds = sysGroupService.listSameGroupUserByUserId(userId);
        Date lastWeekTime = DateUtil.lastWeek();
        List<TaskAnalysisVO> taskAnalysis = taskAccessLogMapper.selectByUserIdsAndLastTime(userIds, lastWeekTime);
        List<TaskAnalysisVO> results = new ArrayList<>();
        taskAnalysis.forEach(taskAnalysisVO->{
            boolean isExists = false;
            for(TaskAnalysisVO r : results) {
                if (taskAnalysisVO.getTaskId().equals(r.getTaskId())) {
                    isExists = true;
                    break;
                }
            }
            if (!isExists) {
                List<TaskResultWithBLOBs> resultWithBlobs = taskResultMapper.getResults(taskAnalysisVO.getTaskId());
                taskAnalysisVO.setCount(resultWithBlobs.size());
                taskAnalysisVO.setHasWritePermission(permissionService.hasWritePerm(userId, taskAnalysisVO.getCreatedBy()));
                taskAnalysisVO.setHasReadPermission(permissionService.hasReadPerm(userId, taskAnalysisVO.getCreatedBy(),
                        taskAnalysisVO.getPassword()));
                taskAnalysisVO.setPassword(null);
                results.add(taskAnalysisVO);
            }
        });
        return results;
    }

    @Override
    public List<AnalysisResultVO> getLastAnalysisResults(Integer userId) {
        List<TaskAnalysisVO> analysisTasks = this.getLastAnalysisTasks(userId);
        List<AnalysisResultVO> analysisResults = new ArrayList<>();

        if (!CollectionUtils.isEmpty(analysisTasks)) {
            analysisTasks.forEach(taskAnalysisVO -> {
                List<TaskResultWithBLOBs> results = taskResultMapper.getResults(taskAnalysisVO.getTaskId());
                if (!CollectionUtils.isEmpty(results)) {
                    results.forEach(taskResult -> {
                        AnalysisResultVO analysisResultVO = new AnalysisResultVO();
                        analysisResultVO.setTaskId(taskAnalysisVO.getTaskId());
                        analysisResultVO.setStatus(taskAnalysisVO.getStatus());
                        analysisResultVO.setTaskName(taskAnalysisVO.getTaskName());
                        analysisResultVO.setPicSvg(serverConfig.parseViewUrl(taskResult.getPicSvg(), 2) );
                        analysisResultVO.setContent(taskResult.getContent());
                        analysisResultVO.setResultId(taskResult.getResultId());
                        analysisResultVO.setResultName(taskResult.getResultName());
                        analysisResultVO.setType(taskResult.getType());
                        analysisResultVO.setUpdateTime(taskResult.getUpdateTime());

                        analysisResultVO.setHasReadPermission(taskAnalysisVO.getHasReadPermission());
                        analysisResultVO.setHasWritePermission(taskAnalysisVO.getHasWritePermission());
                        analysisResults.add(analysisResultVO);
                    });
                }
            });

        }
        return analysisResults;
    }

    @Override
    public Boolean hasWritePermission(Integer userId, Integer taskId) {
        Task task = taskDao.selectByPrimaryKey(taskId);
        return permissionService.hasWritePerm(userId, task.getCreatedBy());
    }

    @Override
    public Boolean getReadPerm(Integer taskId, String password) {
        boolean flag = false;
        Integer userId = UserLoginUtils.getUserId();
        Task task = taskDao.selectByPrimaryKey(taskId);
        if(null != task) {
            if (permissionService.hasReadPerm(userId, task.getCreatedBy(), task.getPassword())) {
                flag = true;
            } else {
                String inputPassword = SecureUtil.md5(password);
                flag = inputPassword.equals(task.getPassword());
            }
        }
        return flag;
    }

    public Boolean hasPermission(Integer userId,Integer createBy){
        boolean permission = false;
        if (userId.equals(createBy)){
            permission = true;
            return permission;
        }
      SysRole sysRole = sysRoleMapper.selectRoleByUserId(userId);
        if ("管理员".equals(sysRole.getRoleName())){
            permission = true;
        }
      return permission;
    }

    public void setPermission(Integer userId, Page<TaskVO> taskInfoVoPage){
        for (TaskVO taskVO : taskInfoVoPage.getResult()) {
            taskVO.setHasReadPermission(permissionService.hasReadPerm(userId, taskVO.getCreatedBy(), taskVO.getPassword()));
            taskVO.setHasWritePermission(permissionService.hasWritePerm(userId, taskVO.getCreatedBy()));

            taskVO.setPermission(hasPermission(userId, taskVO.getCreatedBy()));
            taskVO.setPassword("");
        }
    }
}
